
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
  <head>
    <meta charset="utf-8" />
    <title>4. 构建C/C++扩展 &#8212; Python 3.7.8 文档</title>
    <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <script type="text/javascript" src="../_static/translations.js"></script>
    
    <script type="text/javascript" src="../_static/sidebar.js"></script>
    
    <link rel="search" type="application/opensearchdescription+xml"
          title="在 Python 3.7.8 文档 中搜索"
          href="../_static/opensearch.xml"/>
    <link rel="author" title="关于这些文档" href="../about.html" />
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="copyright" title="版权所有" href="../copyright.html" />
    <link rel="next" title="5. 在Windows平台编译C和C++扩展" href="windows.html" />
    <link rel="prev" title="3. 定义扩展类型：已分类主题" href="newtypes.html" />
    <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
    <link rel="canonical" href="https://docs.python.org/3/extending/building.html" />
    
    <script type="text/javascript" src="../_static/copybutton.js"></script>
    
    
    
    
    <style>
      @media only screen {
        table.full-width-table {
            width: 100%;
        }
      }
    </style>
 

  </head><body>
  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             accesskey="I">索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="windows.html" title="5. 在Windows平台编译C和C++扩展"
             accesskey="N">下一页</a> |</li>
        <li class="right" >
          <a href="newtypes.html" title="3. 定义扩展类型：已分类主题"
             accesskey="P">上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <a href="../index.html">3.7.8 Documentation</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">扩展和嵌入 Python 解释器</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>    

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="building-c-and-c-extensions">
<span id="building"></span><h1><span class="section-number">4. </span>构建C/C++扩展<a class="headerlink" href="#building-c-and-c-extensions" title="永久链接至标题">¶</a></h1>
<p>一个CPython的C扩展是一个共享库(例如一个Linux上的 <code class="docutils literal notranslate"><span class="pre">.so</span></code> ，或者Windows上的 <code class="docutils literal notranslate"><span class="pre">.pyd</span></code> )，其会导出一个 <em>初始化函数</em> 。</p>
<p>为了可导入，共享库必须在 <span class="target" id="index-4"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONPATH"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONPATH</span></code></a> 中有效，且必须命名遵循模块名字，通过适当的扩展。当使用distutils时，会自动生成正确的文件名。</p>
<p>初始化函数的声明如下：</p>
<dl class="function">
<dt id="c.PyInit_modulename">
<a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject">PyObject</a>* <code class="sig-name descname">PyInit_modulename</code><span class="sig-paren">(</span>void<span class="sig-paren">)</span><a class="headerlink" href="#c.PyInit_modulename" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<p>该函数返回完整初始化过的模块，或一个 <a class="reference internal" href="../c-api/module.html#c.PyModuleDef" title="PyModuleDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyModuleDef</span></code></a> 实例。查看 <a class="reference internal" href="../c-api/module.html#initializing-modules"><span class="std std-ref">Initializing C modules</span></a> 了解更多细节。</p>
<p>对于仅有ASCII编码的模块名，函数必须是 <code class="docutils literal notranslate"><span class="pre">PyInit_&lt;modulename&gt;</span></code> ，将 <code class="docutils literal notranslate"><span class="pre">&lt;modulename&gt;</span></code> 替换为模块的名字。当使用 <a class="reference internal" href="../c-api/module.html#multi-phase-initialization"><span class="std std-ref">Multi-phase initialization</span></a> 时，允许使用非ASCII编码的模块名。此时初始化函数的名字是 <code class="docutils literal notranslate"><span class="pre">PyInitU_&lt;modulename&gt;</span></code> ，而 <code class="docutils literal notranslate"><span class="pre">&lt;modulename&gt;</span></code> 需要用Python的 <em>punycode</em> 编码，连字号需替换为下划线。在Python里:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">initfunc_name</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">suffix</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">name</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;ascii&#39;</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">UnicodeEncodeError</span><span class="p">:</span>
        <span class="n">suffix</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;U_&#39;</span> <span class="o">+</span> <span class="n">name</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;punycode&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="sa">b</span><span class="s1">&#39;_&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="sa">b</span><span class="s1">&#39;PyInit&#39;</span> <span class="o">+</span> <span class="n">suffix</span>
</pre></div>
</div>
<p>可以在一个动态库里导出多个模块，通过定义多个初始化函数。而导入他们需要符号链接或自定义导入器，因为缺省时只有对应了文件名的函数才会被发现。查看 <em>&quot;一个库里的多模块&quot;</em> 章节，在 <span class="target" id="index-5"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0489"><strong>PEP 489</strong></a> 了解更多细节。</p>
<div class="section" id="building-c-and-c-extensions-with-distutils">
<h2><span class="section-number">4.1. </span>使用distutils构建C和C++扩展<a class="headerlink" href="#building-c-and-c-extensions-with-distutils" title="永久链接至标题">¶</a></h2>
<p>扩展模块可以用distutils来构建，这是Python自带的。distutils也支持创建二进制包，用户无需编译器而distutils就能安装扩展。</p>
<p>一个distutils包包含了一个驱动脚本 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> 。这是个纯Python文件，大多数时候也很简单，看起来如下：</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>

<span class="n">module1</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span>
                    <span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;demo.c&#39;</span><span class="p">])</span>

<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;PackageName&#39;</span><span class="p">,</span>
       <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;1.0&#39;</span><span class="p">,</span>
       <span class="n">description</span> <span class="o">=</span> <span class="s1">&#39;This is a demo package&#39;</span><span class="p">,</span>
       <span class="n">ext_modules</span> <span class="o">=</span> <span class="p">[</span><span class="n">module1</span><span class="p">])</span>
</pre></div>
</div>
<p>通过文件 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> ，和文件 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code> ，运行如下</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">build</span>
</pre></div>
</div>
<p>这会编译 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code> ，然后产生一个扩展模块叫做 <code class="docutils literal notranslate"><span class="pre">demo</span></code> 在目录 <code class="file docutils literal notranslate"><span class="pre">build</span></code> 里。依赖于系统，模块文件会放在某个子目录形如 <code class="file docutils literal notranslate"><span class="pre">build/lib.system</span></code> ，名字可能是 <code class="file docutils literal notranslate"><span class="pre">demo.so</span></code> 或 <code class="file docutils literal notranslate"><span class="pre">demo.pyd</span></code> 。</p>
<p>在文件 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> 里，所有动作的入口通过 <code class="docutils literal notranslate"><span class="pre">setup</span></code> 函数。该函数可以接受可变数量个关键字参数，上面的例子只使用了一个子集。特别需要注意的例子指定了构建包的元信息，以及指定了包内容。通常一个包会包括多个模块，就像Python的源码模块、文档、子包等。请参数distutils的文档，在 <a class="reference internal" href="../distutils/index.html#distutils-index"><span class="std std-ref">分发 Python 模块（遗留版本）</span></a> 来了解更多distutils的特性；本章节只解释构建扩展模块的部分。</p>
<p>通常预计算参数给 <code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code> ，想要更好的结构化驱动脚本。有如如上例子函数 <a class="reference internal" href="../distutils/apiref.html#distutils.core.setup" title="distutils.core.setup"><code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code></a> 的 <code class="docutils literal notranslate"><span class="pre">ext_modules</span></code> 参数是一列扩展模块，每个是一个 <code class="xref py py-class docutils literal notranslate"><span class="pre">Extension</span></code> 类的实例。例子中的实例定义了扩展命名为 <code class="docutils literal notranslate"><span class="pre">demo</span></code> ，从单一源码文件构建 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code> 。</p>
<p>更多时候，构建一个扩展会复杂的多，需要额外的预处理器定义和库。如下例子展示了这些。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>

<span class="n">module1</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span>
                    <span class="n">define_macros</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">&#39;MAJOR_VERSION&#39;</span><span class="p">,</span> <span class="s1">&#39;1&#39;</span><span class="p">),</span>
                                     <span class="p">(</span><span class="s1">&#39;MINOR_VERSION&#39;</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)],</span>
                    <span class="n">include_dirs</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/usr/local/include&#39;</span><span class="p">],</span>
                    <span class="n">libraries</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;tcl83&#39;</span><span class="p">],</span>
                    <span class="n">library_dirs</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/usr/local/lib&#39;</span><span class="p">],</span>
                    <span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;demo.c&#39;</span><span class="p">])</span>

<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;PackageName&#39;</span><span class="p">,</span>
       <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;1.0&#39;</span><span class="p">,</span>
       <span class="n">description</span> <span class="o">=</span> <span class="s1">&#39;This is a demo package&#39;</span><span class="p">,</span>
       <span class="n">author</span> <span class="o">=</span> <span class="s1">&#39;Martin v. Loewis&#39;</span><span class="p">,</span>
       <span class="n">author_email</span> <span class="o">=</span> <span class="s1">&#39;martin@v.loewis.de&#39;</span><span class="p">,</span>
       <span class="n">url</span> <span class="o">=</span> <span class="s1">&#39;https://docs.python.org/extending/building&#39;</span><span class="p">,</span>
       <span class="n">long_description</span> <span class="o">=</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1">This is really just a demo package.</span>
<span class="s1">&#39;&#39;&#39;</span><span class="p">,</span>
       <span class="n">ext_modules</span> <span class="o">=</span> <span class="p">[</span><span class="n">module1</span><span class="p">])</span>
</pre></div>
</div>
<p>例子中函数 <a class="reference internal" href="../distutils/apiref.html#distutils.core.setup" title="distutils.core.setup"><code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code></a> 在调用时额外传递了元信息，是推荐发布包构建时的内容。对于这个扩展，其指定了预处理器定义，include目录，库目录，库。依赖于编译器，distutils还会用其他方式传递信息给编译器。例如在Unix上，结果是如下编译命令</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">gcc</span> <span class="o">-</span><span class="n">DNDEBUG</span> <span class="o">-</span><span class="n">g</span> <span class="o">-</span><span class="n">O3</span> <span class="o">-</span><span class="n">Wall</span> <span class="o">-</span><span class="n">Wstrict</span><span class="o">-</span><span class="n">prototypes</span> <span class="o">-</span><span class="n">fPIC</span> <span class="o">-</span><span class="n">DMAJOR_VERSION</span><span class="o">=</span><span class="mi">1</span> <span class="o">-</span><span class="n">DMINOR_VERSION</span><span class="o">=</span><span class="mi">0</span> <span class="o">-</span><span class="n">I</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">include</span> <span class="o">-</span><span class="n">I</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">include</span><span class="o">/</span><span class="n">python2</span><span class="mf">.2</span> <span class="o">-</span><span class="n">c</span> <span class="n">demo</span><span class="p">.</span><span class="n">c</span> <span class="o">-</span><span class="n">o</span> <span class="n">build</span><span class="o">/</span><span class="n">temp</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="o">-</span><span class="mf">2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">o</span>

<span class="n">gcc</span> <span class="o">-</span><span class="n">shared</span> <span class="n">build</span><span class="o">/</span><span class="n">temp</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="o">-</span><span class="mf">2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">o</span> <span class="o">-</span><span class="n">L</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">lib</span> <span class="o">-</span><span class="n">ltcl83</span> <span class="o">-</span><span class="n">o</span> <span class="n">build</span><span class="o">/</span><span class="n">lib</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="o">-</span><span class="mf">2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">so</span>
</pre></div>
</div>
<p>这些行代码仅用于展示目的；distutils用户应该相信distutils能正确调用。</p>
</div>
<div class="section" id="distributing-your-extension-modules">
<span id="distributing"></span><h2><span class="section-number">4.2. </span>发布你的扩展模块<a class="headerlink" href="#distributing-your-extension-modules" title="永久链接至标题">¶</a></h2>
<p>当一个扩展已经成功的构建过，有三种方式使用。</p>
<p>最终用户通常想要安装模块，可以这么运行</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">install</span>
</pre></div>
</div>
<p>模块维护者应该制作源码包；要实现可以运行</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">sdist</span>
</pre></div>
</div>
<p>有些情况下，需要在源码发布包里包含额外的文件；这通过 <code class="file docutils literal notranslate"><span class="pre">MANIFEST.in</span></code> 文件实现，查看 <a class="reference internal" href="../distutils/sourcedist.html#manifest"><span class="std std-ref">Specifying the files to distribute</span></a> 了解细节。</p>
<p>如果源码发行包成功构建了，维护者也可以创建二进制发行包。依赖于平台，一个可用的命令如下</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">bdist_wininst</span>
<span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">bdist_rpm</span>
<span class="n">python</span> <span class="n">setup</span><span class="p">.</span><span class="n">py</span> <span class="n">bdist_dumb</span>
</pre></div>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">目录</a></h3>
  <ul>
<li><a class="reference internal" href="#">4. 构建C/C++扩展</a><ul>
<li><a class="reference internal" href="#building-c-and-c-extensions-with-distutils">4.1. 使用distutils构建C和C++扩展</a></li>
<li><a class="reference internal" href="#distributing-your-extension-modules">4.2. 发布你的扩展模块</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="newtypes.html"
                        title="上一章"><span class="section-number">3. </span>定义扩展类型：已分类主题</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="windows.html"
                        title="下一章"><span class="section-number">5. </span>在Windows平台编译C和C++扩展</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../bugs.html">提交 Bug</a></li>
      <li>
        <a href="https://github.com/python/cpython/blob/3.7/Doc/extending/building.rst"
            rel="nofollow">显示源代码
        </a>
      </li>
    </ul>
  </div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             >索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="windows.html" title="5. 在Windows平台编译C和C++扩展"
             >下一页</a> |</li>
        <li class="right" >
          <a href="newtypes.html" title="3. 定义扩展类型：已分类主题"
             >上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <a href="../index.html">3.7.8 Documentation</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" >扩展和嵌入 Python 解释器</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>  
    <div class="footer">
    &copy; <a href="../copyright.html">版权所有</a> 2001-2020, Python Software Foundation.
    <br />
    Python 软件基金会是一个非盈利组织。
    <a href="https://www.python.org/psf/donations/">请捐助。</a>
    <br />
    最后更新于 6月 29, 2020.
    <a href="../bugs.html">发现了问题</a>？
    <br />
    使用<a href="http://sphinx.pocoo.org/">Sphinx</a>2.3.1 创建。
    </div>

  </body>
</html>